/*
 * myHTTPServer.java
 * Author: Helgi Siemsen
 * code from  http://www.prasannatech.net/2008/10/simple-http-server-java.html and then changed so it works for the project
 * @version 1.00 
*/

import java.io.*;
import java.net.*;
import java.util.*;

public class HttpRuServer extends Thread {
	
	static final String HTML_START = 
			"<html>" +
			"<title>Server</title>" +
			"<body>";
			
    static final String HTML_END = 
			"</body>" +
			"</html>";

    //tcp server
	Socket connectedClient = null;	
	BufferedReader inFromClient = null;
	DataOutputStream outToClient = null;
    String portnumber = null;
	//udp server
    DatagramSocket serverSocket = null;
    byte[] receiveData = new byte[1024];
    byte[] sendData = new byte[1024];
    DatagramPacket receivePacket =null;
			
	public HttpRuServer(Socket client) throws Exception{
        connectedClient = client;
        portnumber = Integer.toString(client.getLocalPort());
	}
    public HttpRuServer(DatagramSocket client)throws Exception{
        serverSocket = client;
        portnumber = Integer.toString(client.getLocalPort());
    }
    /*
    UPDserver and additional code in sendResponce is from  http://systembash.com/content/a-simple-java-udp-server-and-udp-client/
    and has been modified to work
     */
    public void UDPserver()
    {

        while(true)
               {
                  try
                  {
                      receivePacket = new DatagramPacket(receiveData, receiveData.length);
                      serverSocket.receive(receivePacket);
                      String sentence = new String( receivePacket.getData());
                      System.out.println("The Client " + serverSocket.getInetAddress() + ":" + serverSocket.getPort() + "is connected");
                      sendResponse(200,sentence);
                  }
                  catch (IOException e)
                  {
                    e.printStackTrace();
                  }
                   catch (java.lang.Exception e)
                  {
                    e.printStackTrace();
                  }
               }
    }
			
	public void run() {
		
		try {
		    System.out.println( "The Client "+ connectedClient.getInetAddress() + ":" + connectedClient.getPort() + " is connected");

            inFromClient = new BufferedReader(new InputStreamReader (connectedClient.getInputStream()));
            outToClient = new DataOutputStream(connectedClient.getOutputStream());

            String requestString=null;
            requestString = inFromClient.readLine();

            int bla = requestString.charAt(0);
            if(bla==65533)
                requestString = requestString.substring(21);

            String headerLine = requestString;

            StringTokenizer tokenizer = new StringTokenizer(headerLine);
			String httpMethod = tokenizer.nextToken();
			String httpQueryString = tokenizer.nextToken();

			StringBuffer responseBuffer = new StringBuffer();
			responseBuffer.append("<b> This is the HTTP Server Home Page.... </b><BR>");
            responseBuffer.append("The HTTP Client request is ....<BR>");
            System.out.println("The HTTP request string is ....");
            System.out.println(requestString);
           	while (inFromClient.ready())
            {
	            // Read the HTTP complete HTTP Query
	            responseBuffer.append(requestString + "<BR>");
				System.out.println(requestString);
				requestString = inFromClient.readLine();
			}

			String index ="<b>Index options </b><BR>" +
                          "<A href=\"http://127.0.0.1:"+ portnumber +"/addNumbers?arg=5+3+4\"> add numbers 5,3 and 4<BR>" +
                          "<A href=\"http://127.0.0.1:"+ portnumber +"/allCaps?arg=asdf\"> allCaps asdf<BR>" +
                          "<A href=\"http://127.0.0.1:"+ portnumber +"/jvmStatus?arg=\"> jvmStatus<BR>";

			if (httpMethod.equals("GET")) {
			  if (httpQueryString.equals("/")) {
		       	// The default home page
				sendResponse(202, index); //requestString.toString()
			  } else {							
				//This is interpreted as a file name
				String fileName = httpQueryString.replaceFirst("/", "");
				if (fileName.contains("addNumbers")||fileName.contains("allCaps")||fileName.contains("jvmStatus")){
				  sendResponse(200, fileName);
				}
				else {
			      sendResponse(404, "<b>The Requested resource not found ....</b>");
				}
			  }										
			} 
			else sendResponse(404, "<b>The Requested resource not found .... </b>");
		} catch (Exception e) {
			e.printStackTrace();
		}		
	}


    public String addNumbers(String variables)
    {
        String[] bla = variables.split("\\+");
        String Result ="";
        int sum=Integer.parseInt(bla[0]);
        Result = bla[0];
        for(int i=1; i<bla.length; i++)
        {
            Result =  Result+"+"+bla[i];
            sum = sum + Integer.parseInt(bla[i]);
        }
        return Result +"=" + sum;
    }
    public String allCaps(String istring)
    {
        istring = istring.replace("%20", " ");
        return istring.toUpperCase();
    }
    public String jvmStatus()
    {
        Runtime s_runtime = Runtime.getRuntime ();
        int totalmem = (int)s_runtime.totalMemory();
        int freemem = (int)s_runtime.freeMemory();
        int memuse = totalmem - freemem;
        return "memory usage: " + memuse + ", total memory: " + totalmem + ", free memory: " + freemem;
    }

	public void sendResponse (int statusCode, String responseString) throws Exception {
		
		String statusLine = null;
		String serverdetails = "Server: Java HTTPServer";
		String contentLengthLine = null;
		String contentTypeLine = "Content-Type: text/html" + "\r\n";
		
		if (statusCode == 200 || statusCode==202)
			statusLine = "HTTP/1.1 200 OK" + "\r\n";
		else
			statusLine = "HTTP/1.1 404 Not Found" + "\r\n";

        if(responseString.contains("addNumbers") && statusCode == 200)
            responseString = addNumbers(responseString.substring(15));
        if(responseString.contains("allCaps") && statusCode == 200)
            responseString = allCaps(responseString.substring(12));
        if(responseString.contains("jvmStatus") && statusCode == 200)
            responseString = jvmStatus();


        //ég lét þetta inn fyrir lol
        //responseString = responseString + " <img src=\"http://www.yoyogames.com/extras/user/image/san2/997/358997/thumb/lol_face.jpg?1293949573\" border=\"0\" alt=\"Funny Pictures\">";

        responseString = HttpRuServer.HTML_START + responseString + HttpRuServer.HTML_END;
        contentLengthLine = "Content-Length: " + responseString.length() + "\r\n";

        if(connectedClient!=null) //tcp
        {
		outToClient.writeBytes(statusLine);
		outToClient.writeBytes(serverdetails);
		outToClient.writeBytes(contentTypeLine);
		outToClient.writeBytes(contentLengthLine);
		outToClient.writeBytes("Connection: close\r\n");
		outToClient.writeBytes("\r\n");		
		

	    outToClient.writeBytes(responseString);
		
		outToClient.close();
        }
        else //udp
        {
            InetAddress IPAddress = receivePacket.getAddress();
            int port = receivePacket.getPort();
            sendData = responseString.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
            serverSocket.send(sendPacket);
        }
	}

			
	public static void main (String args[]) throws Exception {

        if(args.length < 3) //if server
        {
		if(args[0].contentEquals("tcp")){
        ServerSocket Server;
        if(Integer.parseInt(args[1]) > 1024)
            {
                System.out.println ("TCPServer Waiting for client on port " + args[1]);
                Server = new ServerSocket (Integer.parseInt(args[1]), 10, InetAddress.getByName("127.0.0.1"));
            }
            else
            {
                System.out.println ("the socket you picked is under 1024 so now it is 5000 TCPServer Waiting for client on port 5000");
                Server = new ServerSocket (5000, 10, InetAddress.getByName("127.0.0.1"));
            }

            while(true) {
                    Socket connected = Server.accept();
                    (new HttpRuServer(connected)).start();
            }
        }
        else if(args[0].contentEquals("udp")){
                DatagramSocket dataSocket;
                if(Integer.parseInt(args[1]) > 1024) {
                    System.out.println ("UDPServer Waiting for client on port " + args[1]);
                    dataSocket = new DatagramSocket(Integer.parseInt(args[1]),InetAddress.getByName("127.0.0.1"));
                }
                else {
                    System.out.println ("the socket you picked is under 1024 so now it is 5000 UDPServer Waiting for client on port 5000");
                    dataSocket = new DatagramSocket (5000, InetAddress.getByName("127.0.0.1"));
                }
                (new HttpRuServer(dataSocket)).UDPserver();

        }
        else
            System.out.println("error has to be tcp or udp");
        }
        else //if client
        {
            if((args[0].contentEquals("tcp"))&& (args[2]!=null)){
                String str =  args[2];
                tcpClientTest(InetAddress.getByName(str));
            }
            if(args[0].contentEquals("udp"))
            {
                UDPClient(args[1],args[2]);
            }
        }
	}
    public static void connectToServer(String connectionString, InetAddress hostName){
        /**
         * connectToServer(String, InetAddress)
         * Connects to server over tcp
         * Sends a http request string to the server and closes
         */
        try{
            String serverReply;
            BufferedReader inFromUser = new BufferedReader( new InputStreamReader(System.in));
            Socket sock = new Socket(hostName, 5000);
            DataOutputStream sendMsg = new DataOutputStream(sock.getOutputStream());
            BufferedReader inFromServer = new BufferedReader(new InputStreamReader(sock.getInputStream()));
            sendMsg.writeBytes(connectionString + '\n');
            serverReply = inFromServer.readLine();
            if(serverReply==null){
                System.out.println("SERVER ERROR  NO REPLY" + serverReply);               
            }
            System.out.println("SERVER REPLY " + serverReply);
        }catch(SocketException e){
            System.out.println("Socket Exception in connectToServer: " + e.getMessage());
            System.out.println("Socket Exception in connectToServer: " + e.getStackTrace());
        }
        catch (Exception e){
            System.out.println("Error in  connectToServer: " +e.getMessage());
            System.out.println("Error in  connectToServer: "+ e.getStackTrace());
        }
    }
    public static void tcpClientTest( InetAddress hostName){
        /**
         * tcpClientTest(InetAddress)
         * Sends various http connection strings to the http server
         * through tcp client connectToServer(String, InetAddress)
         */
        try{
            for(int i=0; i<5; i++){
                if (i==0){
                    System.out.println("Sending [GET / ] Expected reply: HTTP/1.1 200 OK");
                    connectToServer( "GET / ",hostName) ;
                }if (i==1){
                    System.out.println("Sending [GET /addNumbers?arg=5+3+4 ] Expected reply: HTTP/1.1 200 OK");
                    connectToServer("GET /addNumbers?arg=5+3+4 ",hostName);
                }if (i==2){
                    System.out.println("Sending [GET /stuff ] Expected reply: HTTP/1.1 404 Not Found");
                    connectToServer("GET /stuff ",hostName);
                }if (i==3){
                    System.out.println("Sending [GET /allCaps?arg=asdf ] Expected reply: HTTP/1.1 200 OK");
                    connectToServer("GET /allCaps?arg=asdf ",hostName);
                }if (i==4){
                    System.out.println("Sending [GET /jvmStatus?arg= ] Expected reply: HTTP/1.1 200 OK");
                    connectToServer("GET /jvmStatus?arg= ",hostName);
                }
            }
        }
        catch(Exception e){
            System.out.println("Error in TcpClientTest:"+ e.getMessage());
            System.out.println("Error in TcpClientTest:"+ e.getStackTrace());
        }
    }

    /*
    UPDClient is copied from http://systembash.com/content/a-simple-java-udp-server-and-udp-client/ and then modified to work
    there is no extended testing because the UPD server can't handle it
     */
    public static void UDPClient(String host,String inIP) throws Exception
    {
      DatagramSocket clientSocket = new DatagramSocket();
      InetAddress IPAddress = InetAddress.getByName(inIP);
      byte[] sendData = new byte[1024];
      byte[] receiveData = new byte[1024];
      System.out.println("the UPDClient only test \"Get /jvmStatus?arg= \" because there is no need to test more");
      String sentence = "GET /jvmStatus?arg= ";
      sendData = sentence.getBytes();
      DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(host));
      clientSocket.send(sendPacket);
      DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
      clientSocket.receive(receivePacket);
      String modifiedSentence = new String(receivePacket.getData());
      System.out.println("FROM SERVER:" + modifiedSentence);
      clientSocket.close();
    }
}
